package de.klingbeil.hhc.locator.ui;

import javax.persistence.EntityManager;

import org.hibernate.proxy.HibernateProxyHelper;
import org.springframework.orm.jpa.support.SharedEntityManagerBean;

import com.google.web.bindery.requestfactory.shared.Locator;

import de.klingbeil.hhc.core.domain.Identifiable;
import de.klingbeil.hhc.core.util.Assert;

public class GenericEntityLocator<T extends Identifiable<Long>> extends
		Locator<T, Long> {

	private EntityManager entityManager;

	public GenericEntityLocator() {
		this(getEntityManager());
	}

	public GenericEntityLocator(EntityManager entityManager) {
		this.entityManager = entityManager;
	}

	@Override
	public T create(Class<? extends T> clazz) {
		try {
			return clazz.newInstance();
		} catch (InstantiationException e) {
			throw new RuntimeException(e);
		} catch (IllegalAccessException e) {
			throw new RuntimeException(e);
		}
	}

	@Override
	public Long getId(T domainObject) {
		Assert.isNotNull(domainObject, "domainObject");

		return domainObject.getId();
	}

	@Override
	public Class<Long> getIdType() {
		return Long.class;
	}

	@Override
	public Class<T> getDomainType() {
		throw new UnsupportedOperationException(
				"getDomainType() is not used by GWT RequestFactory and therefore not implemented.");
	}

	@Override
	public Long getVersion(T domainObject) {
		Assert.isNotNull(domainObject, "domainObject");

		return domainObject.getVersion();
	}

	@Override
	public T find(Class<? extends T> clazz, Long id) {
		return entityManager.find(clazz, id);
	}

	@Override
	public boolean isLive(T domainObject) {
		Class<T> clazz = getClass(domainObject);
		return find(clazz, getId(domainObject)) != null;
	}

	@SuppressWarnings("unchecked")
	private Class<T> getClass(T domainObject) {
		return HibernateProxyHelper
				.getClassWithoutInitializingProxy(domainObject);
	}

	private static EntityManager getEntityManager() {
		return SpringServiceLocator.getTypedInstance(
				SharedEntityManagerBean.class).getObject();
	}
}
